use std::cmp::Ordering;
use std::fmt::{Debug, Display, Formatter};
use std::fs::{File, OpenOptions};
use std::future::Future;
use std::iter::zip;
use std::mem;
use std::mem::MaybeUninit;
use std::ops::{Add, Deref, DerefMut, Range, RangeFrom};
use std::path::Path;
use std::pin::Pin;
use std::ptr::NonNull;
use std::str::FromStr;
use std::sync::Arc;
use std::thread::sleep;
use std::time::Duration;
use chrono::{Datelike, DateTime, Local, NaiveDate, Weekday};

use lazy_static::lazy_static;
use rand::random;
use time::Date;

pub use ptr_model::*;

pub use crate::utils::cache_model::CacheCap;
pub use crate::utils::thread_pool::{MultiThreadTester};

pub mod cache_model;
pub mod multi_cond;
pub mod ptr_model;
pub mod thread_pool;
pub mod error_cast;
pub mod iter_ext;
pub type DynFn = dyn Fn() -> () + Send + 'static;
pub type DynFnOnce = dyn FnOnce() -> () + Send + 'static;
pub type DynFnMut = dyn FnMut() -> () + Send + 'static;

/// 快速包装函数用
#[macro_export]
macro_rules! box_fn {
    ($func:expr) => {
        Box::new($func) as Box<DynFn>
    };
}

#[macro_export]
macro_rules! box_fn_mut {
    ($func:expr) => {
        Box::new($func) as Box<DynFnMut>
    };
}

#[macro_export]
macro_rules! box_fn_once {
    ($func:expr) => {
        Box::new($func) as Box<DynFnOnce>
    };
}

/// 和mem::write不同，=会自动drop原有的变量，write不会触发此操作
/// 不安全的赋值操作
#[macro_export]
macro_rules! unsafe_assign {
    ($e:expr,$val:expr) => {
        unsafe {
            *(&$e as *const _ as *mut _) = $val;
        }
    };
}
///用于获取变量的可变引用
#[macro_export]
macro_rules! to_mut_ref {
    ($e:expr,$t:ty) => {
        unsafe {
            #[allow(invalid_reference_casting)]
             &mut *($e as *const _ as *mut $t)
             }
    };
}
/// # Example
/// 方便的固定一个数据
/// pin可以固定栈空间和堆空间的数据，防止移动的时候内部数据的地址被改变
/// box通常只能在堆空间上分配，如果面对函数的地址处理会有额外的分配开销
/// 使用案例，
/// 1.
/// ```
/// safe_pin!{
///     let msg = "test_str".to_string();
/// }
/// let mut_msg = msg.as_mut();
/// ```
/// 2.
///  ```
/// let code = "is right space".to_string();
/// safe_pin!(code);
/// //后续的code都是pin, 把之前的给shadow了，可以始终保证，
/// //即使是在栈空间上其所有权的变量生命周期依旧是安全的
/// let mut_code = code.as_mut();
///
///  ```
#[macro_export]
macro_rules! safe_pin {
    ($($x:ident),*) => { $(
        // Move the value to ensure that it is owned
        let mut $x = $x;
        // Shadow the original binding so that it can't be directly accessed
        // ever again.
        #[allow(unused_mut)]
        let mut $x = unsafe {
            std::pin::Pin::new_unchecked(&mut $x)
        };
    )* };
    ($(
            let $x:ident = $init:expr;
    )*) => {
        $(
            let $x = $init;
            $crate::safe_pin!($x);
        )*
    };
}
/// 用法同safe_pin!
#[macro_export]
macro_rules! thread_safe_ptr {
    ($($x:ident),*) => { $(
        let $x = $x;
        let mut $x = unsafe {
            $crate::utils::ThreadSafePtr::capture(& $x)
        };
    )* };
    ($(
            let $x:ident = $init:expr;
    )*) => {
        $(
            let $x = $init;
            $crate::thread_safe_ptr!($x);
        )*
    };
}

#[macro_export]
macro_rules! thread_safe_slice {
    ($($x:ident),*) => { $(
        let $x = $x;
        let mut $x = unsafe {
            $crate::utils::ThreadSafePtr::capture_slice($x)
        };
    )* };
    ($(
            let $x:ident = $init:expr;
    )*) => {
        $(
            let $x = $init;
            $crate::thread_safe_slice!($x);
        )*
    };
}


/// 定义一个获取cacheCap的macro
#[macro_export]
macro_rules! cache_cap {
    ($i:expr) => {
       $crate::utils::cache_model::CacheCap::of(move || {$i})
    };
}

/// 快速压测用宏
#[macro_export]
macro_rules! multi_tester {
    ($($f:expr),*) => {{
        let mut tmp_tester =  crate::utils::thread_pool::MultiThreadTester::new();
        $(tmp_tester.append_test(
            stringify!($f),
            move ||{$f},
            10
        );)*
        tmp_tester.run();
    }};
}





#[test]
fn tt() {
    safe_pin! {
        let msg = "asd".to_string();
    }
    println!("{:?}", msg);
    let x1 = msg.get_mut();
    *x1 = "ok".to_owned();
    println!("{:?}", x1);
}

#[test]
fn thread_safe() {
    let option = Some(1);
    thread_safe_ptr! {
        let a = 1;
    }
    let x = a;
    let x1 = x.deref();
    println!("{x1}")
}

#[test]
fn thread_safe_some() {
    thread_safe_ptr! {
        let a = Some(1);
    }
    a.read_write_ops(|e| {
        println!("{e}");
        Some(12)
    });
    println!("{a:?}");
}

fn find_centre_point(mut nums: Vec<i32>) -> i32 {
    let len = nums.len();
    match len {
        0 => -1,
        1 => 0,
        _ => {
            let total_value = nums.iter().fold(0, |a, b| a + b);
            let mut p = 0;
            let mut tmp = 0;
            for i in 0..len {
                if total_value - nums[i] == tmp * 2 {
                    return p;
                }
                p = p + 1;
                tmp = tmp + nums[i];
            }
            -1
        }
    }
}

#[test]
fn test_array() {
    let mut test_vec = vec![1, -1, 2];

    println!("{}", find_centre_point(test_vec));
}


#[test]
fn test_create_md_files() {
    let final_base_dir = "D:/WORK_MD".to_owned();
    //

    let ymd_date = |y, m, d| NaiveDate::from_ymd_opt(y, m, d).unwrap();
    let mut base_date = ymd_date(2024, 01, 01);
    (0..30).into_iter().for_each(|i| {
        if [Weekday::Sat, Weekday::Sun].iter().all(|a| *a != base_date.weekday()) {
            let tmp = final_base_dir.clone() + &*format!("/{}.md", base_date.to_string());
            let path = Path::new::<str>(tmp.as_ref());
            if !path.exists() {
                OpenOptions::new()
                    .read(true)
                    .write(true)
                    .create_new(true)
                    .open(tmp).unwrap();
            }
        }
        base_date = base_date + chrono::Duration::days(1);
    });
}

fn swrr(weight_arr: &Vec<i32>, times: usize) -> Vec<usize> {
    let sum = weight_arr.iter().sum::<i32>();
    let mut weight_vec = weight_arr.iter().enumerate().map(|(i, e)| (i, *e, *e)).collect::<Vec<_>>();
    (0..times).map(|_| {
        let pos = weight_vec.iter().max_by_key(|e| (**e).2).unwrap().0;
        weight_vec[pos].2 -= sum;
        weight_vec.iter_mut().for_each(|e| {
            e.2 += e.1;
        });
        pos
    }).collect()
}

#[test]
fn test_swrr()
{
    let vec1 = swrr(&vec![1, 2, 3, 4], 20);
    println!("{vec1:?}")
}
